package tp.badugi.client;

import java.io.IOException;

import tp.badugi.bot.GuiClientWithBot;
import tp.badugi.client.exceptions.TableNotCreatedClientException;
import tp.badugi.client.exceptions.TableNotJoinedClientException;
import tp.badugi.net.ClientNetworkingChannel;
import tp.badugi.net.GameStatus;
import tp.badugi.net.exceptions.IllegalCharactersException;
import tp.badugi.net.exceptions.IllegalParameterValueException;
import tp.badugi.net.exceptions.NameTakenException;
import tp.badugi.net.exceptions.NoSuchTableException;
import tp.badugi.net.exceptions.RequestTimedOutException;
import tp.badugi.net.exceptions.ServerCouldNotCompleteRequestException;
import tp.badugi.net.exceptions.TableFullException;

public class ClientBridgeAdapter implements iClientBridgeAdapter{
	private ClientNetworkingChannel communicationChannel;
	private iClientFrontAdapter frontAdapter;
	
	public GameStatus gameStatus = null;
	private double gameMinimalRaiseMultiplier = 1.0;
	
	private String serverIpAddress = "";
	private int serverPortNumber = -1;
	public String[] serverTableList;
	
	ClientBridgeAdapter(GuiClient frontClient){
		this.frontAdapter = frontClient;
	}
	
	public ClientBridgeAdapter(GuiClientWithBot frontClient){
		this.frontAdapter = frontClient;
	}

	//--------------------Client to server methods	
	
	@Override
	public void connect(String ipAddress, int portNumber) 
			throws IOException, ServerCouldNotCompleteRequestException,
			RequestTimedOutException{
		
		GameListener gameListener = new GameListener(this);
		this.communicationChannel = new ClientNetworkingChannel(ipAddress, portNumber,gameListener,gameListener);
		gameListener = null;
		try{
			this.communicationChannel.connect();
			
			this.serverIpAddress = ipAddress;
			this.serverPortNumber = portNumber;
			this.serverTableList = this.communicationChannel.getTableList();
			
			this.passConnectionMessage("Succesfullty connected to server!\n"+this.serverIpAddress+" "+this.serverPortNumber);
			
			this.frontAdapter.showServerView(this.serverIpAddress, this.serverPortNumber, this.serverTableList);
		}
		catch(IOException | ServerCouldNotCompleteRequestException | RequestTimedOutException ex){
			throw ex;
		}		
	}

	@Override
	public void disconnectFromServer() throws IOException{
		try{
			this.communicationChannel.disconnect();
			
			if(this.gameStatus == null || this.gameStatus.tableName.equals("")){
				this.passConnectionMessage("Succesfully disconnected from server.\n "+this.serverIpAddress+":"+this.serverPortNumber);
			}
			else{
				this.passConnectionMessage("Game quitted "+this.gameStatus.tableName);
				this.passConnectionMessage("Succesfully disconnected from server.\n "+this.serverIpAddress+":"+this.serverPortNumber);
			}

			this.gameStatus = null;
			this.serverIpAddress = "";
			this.serverPortNumber = -1;
			
			this.frontAdapter.showConnectionView();
		} catch(IOException ioe){
			throw ioe;
		}
	}

	@Override
	public void disconnectAndExitProgram() throws IOException{
		try{
			this.communicationChannel.disconnect();
			System.exit(0);
		}
		catch(IOException ioe){
			throw ioe;
		}
		
	}
	
	@Override
	public void reconnect(String ipAdress, int port, String tableName,
			String myName) {
		
	}

	@Override
	public void joinTable(String tableName, String myNickname) 
			throws TableFullException, IllegalArgumentException, IllegalCharactersException,
			ServerCouldNotCompleteRequestException, NameTakenException,
			NoSuchTableException, RequestTimedOutException, TableNotJoinedClientException
	{
		try{			
			this.gameStatus = 
				this.communicationChannel.joinTable(tableName, myNickname);
			
			if (this.gameStatus != null){
				this.frontAdapter.showGameView(this.gameStatus, this.serverIpAddress, this.serverPortNumber);
				
				this.frontAdapter.writeConsoleMessage("Table joined!");
			}
			else{
				throw new TableNotJoinedClientException("Error occured! Table not joined!");
			}
		}
		catch (TableFullException | IllegalArgumentException | IllegalCharactersException |
				ServerCouldNotCompleteRequestException | NameTakenException |
				NoSuchTableException | RequestTimedOutException |
				TableNotJoinedClientException ex) {
			throw ex;
		}
	}

	@Override
	public void refreshTableList()
			throws ServerCouldNotCompleteRequestException, RequestTimedOutException {
		try{
			this.serverTableList = this.communicationChannel.getTableList();
			this.frontAdapter.showServerView(this.serverIpAddress, this.serverPortNumber, this.serverTableList);
		}
		catch(ServerCouldNotCompleteRequestException | RequestTimedOutException ex){
			throw ex;
		}
	}
	
	@Override
	public void leaveTable() throws ServerCouldNotCompleteRequestException,
			RequestTimedOutException {
		try{
			this.communicationChannel.leaveTable();
			
			this.serverTableList = this.communicationChannel.getTableList();
			
			this.frontAdapter.showServerView(this.serverIpAddress, this.serverPortNumber, this.serverTableList);
			
			this.passConnectionMessage("Game quitted "+this.gameStatus.tableName);
			
			this.gameStatus.tableName = "";
			this.gameStatus = null;
		}
		catch(ServerCouldNotCompleteRequestException| RequestTimedOutException ex){
			throw ex;
		}
	}

	@Override
	public void createTable(String tableName, String myNickname, int tableSize, long startingChips,
							long smallBlind, long bigBlind) 
			throws NameTakenException, IllegalCharactersException, IllegalParameterValueException,
			ServerCouldNotCompleteRequestException, RequestTimedOutException, 
			TableNotCreatedClientException
	{
		try{			
			this.gameStatus
				= this.communicationChannel.createTable(tableName, myNickname, tableSize,
														startingChips, smallBlind, bigBlind);
			
			if (!(this.gameStatus == null)){
				this.frontAdapter.writeConnectionMessage("Table created!");
				
				this.frontAdapter.showGameView(this.gameStatus, this.serverIpAddress, this.serverPortNumber);
				
				this.frontAdapter.writeConsoleMessage("Table joined!");
			}
			else{
				throw new TableNotCreatedClientException("Error occured! Table not created!");
			}
		}
		catch(NameTakenException | IllegalCharactersException | IllegalParameterValueException |
				ServerCouldNotCompleteRequestException | RequestTimedOutException |
				TableNotCreatedClientException ex){
			throw ex;
		}
		
	}

	@Override
	public void changeCards(String[] cardsToChange) {
		this.communicationChannel.respondToCardsRequest(cardsToChange);		
	}

	@Override
	public void makeAction(String action, long amountOfChips) {
		this.communicationChannel.respondToActionRequest(action, amountOfChips);
	}

	@Override
	public void Shuffle() {
	}
	//--------------------Client to server methods ^
	
	//-----------------------Server to client methods
	
	@Override
	public void passErrorMessage(String errorMessage) {
		this.frontAdapter.writeErrorMessage(errorMessage);
	}

	@Override
	public void passConnectionMessage(String connectionMessage) {
		this.frontAdapter.writeConnectionMessage(connectionMessage);
	}

	@Override
	public void passValidationMessage(String validationMessage) {
		this.frontAdapter.writeValidationMessage(validationMessage);
	}

	@Override
	public void updateGameAndConsole(String consoleMessage) {
		this.frontAdapter.writeConsoleMessage(consoleMessage);
		this.updateGameStatus();
	}
	
	@Override
	public void updateGameStatus() {
		this.frontAdapter.updateGameData(this.gameStatus,this.serverIpAddress,this.serverPortNumber);
	}

	@Override
	public void passCardRequest(int cardChangetimeout){
		this.frontAdapter.showCardChangeView(this.gameStatus.myCards, cardChangetimeout);
	}
	
	@Override
	public void passActionRequest(String[] possibleActions, int actionTimeout){
		int myPlayerNumber = this.gameStatus.myPlayerNumber;
		long myCurrentPotContribution = this.gameStatus.playerPotContributions[myPlayerNumber];
		long currentBet = this.gameStatus.betAmount;
		
		long currentBetDifference = currentBet - myCurrentPotContribution;
		
		long minimalRaise = (long)((double)currentBet * this.gameMinimalRaiseMultiplier);
		
		this.frontAdapter.showActionView(possibleActions, actionTimeout, currentBetDifference, minimalRaise);
	}

	@Override
	public void passWinnerView(String[][] revealedPlayersCards, String[] winnersNames, 
			long[] chipsAddedFromPot, int[] winnersIndexes) {
		this.frontAdapter.showRoundWinnerView(revealedPlayersCards, winnersNames,
				chipsAddedFromPot, winnersIndexes);
	}

	@Override
	public void emergrncyClientReset(){
		this.gameStatus = null;
		
		this.serverIpAddress = "";
		this.serverPortNumber = -1;
		this.serverTableList = null;
		
		this.frontAdapter.showConnectionView();
	}
	
	//-----------------------Server to client methods^

	// ----------------------Client request methods
	@Override
	public GameStatus getGameStatus() {
		return this.gameStatus;
	}
	
	// ----------------------Client request methods ^
}
